// HybridMontecarlo interface
//////////////////////////////////////////////////////////////////////////////

#if !defined(CONTINUOUS_TABUSEARCH_H)
#define CONTINUOUS_TABUSEARCH_H

# include <iostream>
using namespace std;
# include <cmath>
#include <vector>
# include "Function.h"
# include "tabulist.h"
#include "promlist.h"
# include "Regulator.h"

class ContinuousTabuSearch
{
  friend ostream &operator<<(ostream &os, ContinuousTabuSearch &X);

  public : 
    ContinuousTabuSearch(int numDimension, int numNeighSol, double maxRadius, double tabuRadius,
                double promRadius, int maxTabuListSize, int maxPromlistSize, Function *Func);

	  virtual ~ContinuousTabuSearch() 
		{
      deleteA(m_Phi);
      deleteA(m_Cos);
		}

    void Initialise(double maxRadius, double tabuRadius, double promRadius);
	  void doRun(double *solution, int maxIterations, string& directory);
    void doRunDiagnosis(double *solution, int maxIterations, char filename[], char filecoord[], string& directory);

    double BestSoFar(double *solution);

	  // used to reset the function value to the value of the initial solution 
	  void ResetTracker(double *I)
	  {
		  double x;

      //x = StoredFunction->NormValue(I);
		  x = StoredFunction->Value(I);

		  StoredFunction->Result.ResetWith(x,I);
	  }

	  void PrintOpenNewFileForRegulator(char lName[])
	  {
		  HypersphereRegulator.PrintOpenNewFile(lName);
	  }

    void testHypercube(double *solution, double innerEdge, double outerEdge, int neighSol);

  private :

    // returns random in last argument randomPoint. 
    void pickRandomPointInShell(double* solution, double innerRadius, double outerRadius, int neighSol);
    void pickRandomPointInCube(double *solution, double innerEdge, double outerEdge, int neighSol);

    // used only by pickRandomPointInShell()
    void convertCartesian(double randomRadii, double *angle, vector<double> &neighSolArray);

    // populate m_radii
    // m_radii contain all the radii which define our shells 
    void createRadii(double maxRadius, double minRadius);
    void createCube(double maxEdge, double minEdge);

    // populate m_neighSolution
    void neighbour(double *solution);

    // used to test pickRandomPointInShell and 
    // convertCartesian
    void test(double innerRadius, double outerRadius);

    int m_NumDimension;                    // Number of dimensions
    int m_MaxIterations;                  // Number of iterations
	  int m_NumNeighSol;                    // Number of neighbouring points
    int m_maxTabulistSize;                // Max tabu list size
    int m_maxPromlistSize;                // Max promising list size

    int nPromNoCall;
    int nFuncNoCall;
    int nReduction;

    double l_tabuRadius;
    double l_maxRadius;
    double m_tabuRadius;                  // Radius of the tabu sphere
    double m_promRadius;                  // Radius of the promising sphere
    double m_maxRadius;                   // Max radius of the hyperspheres
    double bestForThisIteration;          // bestForThisIteration stores the best function value for the
                                          // current iteration
    double worstForThisIteration;
    double cgmBestForThisIteration;       // stores the best function value after the CGM has been invoked
    double simpBestForThisIteration;
    double doshSimpBestForThisIteration;
    double origValue;                     // stores the value of the current solution
    double m_RanRadii;                    // stores the value of the random radii
    double *m_Ran;
    double funcval;
    double thresholdValue;

    double *m_Phi;                        // array used to store the n-1 angles
    double *m_Sin;                        // stores the Sine value of the angles
    double *m_Cos;                        // stores the Cosine value of the angles
    
 
    Tabulist m_Tabulist;      // Creates the tabu list object
    Promlist m_Promlist;

    vector< vector<double> > m_neighSolution;
    vector<double> m_radii;  // must end up with size = m_NumNeighSol + 1

	  Regulator	HypersphereRegulator;

	  Function *StoredFunction;             // the function

};

#endif // !defined(CONTINUOUS_TABUSEARCH_H)
